#if VS_TESSELLATION

struct HS_CONTROL_POINT_OUTPUT_MOTIONBLUR
{
	hsControlPointShared controlPoint;
#if HIQ_MOTIONBLUR
	hsControlPointShared controlPointPrev : CONTROL_POINT_COMMON;
	float4x4 matWVP : MATRIX_WVP;
#else
	float4 vVelocity     : CONTROL_POINT_MB_SPECIFIC0;
	float4 vVelocityPrev : CONTROL_POINT_MB_SPECIFIC1;
#endif
};

///////////////// hull shader //////////////////

HS_CONSTANT_DATA_OUTPUT MotionBlurPassConstantsHS(InputPatch<vert2fragMotionBlur, 3> p, uint PatchID : SV_PrimitiveID)
{
	const float3 vP0 = p[0].vView.xyz + g_VS_WorldViewPos.xyz;
	const float3 vP1 = p[1].vView.xyz + g_VS_WorldViewPos.xyz;
	const float3 vP2 = p[2].vView.xyz + g_VS_WorldViewPos.xyz;
	HS_CONSTANT_DATA_OUTPUT output = CommonConstantsHS(vP0, vP1, vP2, g_VS_WorldViewPos.xyz, g_VS_WorldViewPos.xyz, PatchID);

	return output;
}

[domain("tri")]
[partitioning("fractional_odd")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("MotionBlurPassConstantsHS")]
[maxtessfactor(MAX_TESS_FACTOR)]
HS_CONTROL_POINT_OUTPUT_MOTIONBLUR Common_MotionBlurPassHS(InputPatch<vert2fragMotionBlur, 3> inputPatch, uint uCPID : SV_OutputControlPointID)
{
	HS_CONTROL_POINT_OUTPUT_MOTIONBLUR	output = (HS_CONTROL_POINT_OUTPUT_MOTIONBLUR)0;

	output.controlPoint.vView       = inputPatch[uCPID].vView;
	output.controlPoint.vNormal     = inputPatch[uCPID].vNormal.xyz;
	output.controlPoint.vBaseTC     = inputPatch[uCPID].baseTC;
#if HIQ_MOTIONBLUR
	output.controlPointPrev.vView   = inputPatch[uCPID].vViewPrev;
	output.controlPointPrev.vNormal = inputPatch[uCPID].vNormalPrev.xyz;
	output.controlPointPrev.vBaseTC = inputPatch[uCPID].baseTC;
	output.matWVP                   = inputPatch[uCPID].matWVP;
#else
	output.vVelocity                = inputPatch[uCPID].vVelocity;
	output.vVelocityPrev            = inputPatch[uCPID].vVelocityPrev;
#endif

	return output;
}

///////////////// domain shader //////////////////

void FillEvalInput_MB(in HS_CONTROL_POINT_OUTPUT_MOTIONBLUR triPatch[3], in HS_CONSTANT_DATA_OUTPUT hsConstData, in float3 vBaryCoords, inout CommonEvaluationInputDS evalInput)
{
	evalInput.vBaryCoords = vBaryCoords;
	FillEvalInputControlPoint(triPatch[0].controlPoint, triPatch[1].controlPoint, triPatch[2].controlPoint, hsConstData, evalInput);
	evalInput.bRelativePos = true;
	evalInput.vViewPos = g_VS_WorldViewPos.xyz;
}

void ProcessEvalOutput(in CommonEvaluationOutputDS evalOutput, inout vert2fragMotionBlur dsOutput)
{
	dsOutput.baseTC    = evalOutput.vBaseTC;
	dsOutput.HPosition = mul(g_VS_ViewProjZeroMatr, float4(evalOutput.vPos.xyz, 1));
}

[domain("tri")]
vert2fragMotionBlur Common_MotionBlurPassDS( HS_CONSTANT_DATA_OUTPUT hsConstData, float3 vBaryCoords : SV_DomainLocation, const OutputPatch<HS_CONTROL_POINT_OUTPUT_MOTIONBLUR, 3> TrianglePatch )
{
	vert2fragMotionBlur output = (vert2fragMotionBlur)0;

	// Evaluate current position
	CommonEvaluationInputDS evalInput = (CommonEvaluationInputDS)0;
	{
		FillEvalInput_MB(TrianglePatch, hsConstData, vBaryCoords, evalInput);
		CommonEvaluationOutputDS evalOutput;
		Evaluate(evalInput, evalOutput);
		ProcessEvalOutput(evalOutput, output);
	}

#if HIQ_MOTIONBLUR
	// Evaluate previous position
	{
		CommonEvaluationInputDS evalInputPrev = evalInput;
		FillEvalInputControlPoint(TrianglePatch[0].controlPointPrev, TrianglePatch[1].controlPointPrev, TrianglePatch[2].controlPointPrev, hsConstData, evalInputPrev);
		CommonEvaluationOutputDS evalOutputPrev;
		Evaluate(evalInputPrev, evalOutputPrev);

		const float4 HPosition = output.HPosition;
		const float4 HPositionPrev = mul(TrianglePatch[0].matWVP, float4(evalOutputPrev.vPos.xyz, 1));

		// Compute screen space position
		output.vVelocity = HPosToScreenTC( HPosition );
		output.vVelocityPrev = HPosToScreenTC( HPositionPrev );
	}
#else
	output.vVelocity = EvalVec(TrianglePatch[0].vVelocity, TrianglePatch[1].vVelocity, TrianglePatch[2].vVelocity, vBaryCoords);
	output.vVelocityPrev = EvalVec(TrianglePatch[0].vVelocityPrev, TrianglePatch[1].vVelocityPrev, TrianglePatch[2].vVelocityPrev, vBaryCoords);
#endif

	return output;
}

#endif